<?php
namespace App\Library\Custom;

class Util
{
    //保存类实例的静态成员变量
    private static $_instance;

    private function __construct()
    {
    }

    /**
     * Get an instance of the {@link Inflector} class.
     *
     * @return object
     */
    public static function getInstance()
    {
        if(!(self::$_instance instanceof self)){
            self::$_instance = new self;
        }
        return self::$_instance;
    }

    /**
     * Convert a camelized string to a lowercase, underscored string.
     * 把驼峰法命名转换为小写并用下划线连接
     *
     * @param string $s string to convert
     * @return string
     */
    public function uncamelize($s)
    {
        $normalized = '';

        for ($i=0,$n=strlen($s); $i<$n; ++$i)
        {
            if (ctype_alpha($s[$i]) && self::is_upper($s[$i]))
                $normalized .= '_' . strtolower($s[$i]);
            else
                $normalized .= $s[$i];
        }
        return trim($normalized,' _');
    }

    /**
     * Turn a string into its camelized version.
     * 把一个字符串转换为驼峰法命名
     *
     * @param string $s string to convert
     * @return string
     */
    public function camelize($s)
    {
        $s = preg_replace('/[_-]+/','_',trim($s));
        $s = str_replace(' ', '_', $s);

        $camelized = '';

        for ($i=0,$n=strlen($s); $i<$n; ++$i)
        {
            if ($s[$i] == '_' && $i+1 < $n)
                $camelized .= strtoupper($s[++$i]);
            else
                $camelized .= $s[$i];
        }

        $camelized = trim($camelized,' _');

        if (strlen($camelized) > 0)
            $camelized[0] = strtolower($camelized[0]);

        return $camelized;
    }


    /**
     * Determines if a string contains all uppercase characters.
     * 确定一个字符串包含大写字母
     *
     * @param string $s string to check
     * @return bool
     */
    public static function is_upper($s)
    {
        return (strtoupper($s) === $s);
    }

    /**
     * Determines if a string contains all lowercase characters.
     * 确定一个字符串是否包含所有的小写字符。
     *
     * @param string $s string to check
     * @return bool
     */
    public static function is_lower($s)
    {
        return (strtolower($s) === $s);
    }

    /**
     * Convert a string with space into a underscored equivalent.
     * 将一个空格转换成一个带有空格的字符串。
     *
     * @param string $s string to convert
     * @return string
     */
    public function underscorify($s)
    {
        return preg_replace(array('/[_\- ]+/','/([a-z])([A-Z])/'),array('_','\\1_\\2'),trim($s));
    }

    public function keyify($class_name)
    {
        return strtolower($this->underscorify(denamespace($class_name))) . '_id';
    }

    /**
      * Recursively create a directory
      */
    public static function createDir($dir, $mode=0777)
    {
        if(!is_dir($dir)) {
            self::createDir(dirname($dir), $mode);
            mkdir($dir, $mode);
        }
        return true;
    }

    /**
     * 随机生成Token（30位随机数）
     */
    public static function getToKen($leng = 30){
        $str = '';
        $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
        $max = strlen($strPol)-1;
        for($i=0;$i<$leng;$i++){
            //$str .= substr($strPol, rand(0,$max),1);
            $str .= $strPol[rand(0,$max)];//rand($min,$max)生成介于min和max两个数之间的一个随机整数
        }
        return $str;
    }

    /**
     * 随机
     * @param unknown $length
     * @return string
     */
    public static function randomkeysNumber($length = 6)
    {
        $arr = Array('1','2','3','4','5','0','6','7','8','9');//定义数组
        shuffle($arr);//打乱元素顺序
        $rand = array_slice($arr,0,6);//取前四个元素
        $result=implode('',$rand);//转成字符串
        return $result;
    }

    public static function uuid($prefix = '') {
        $chars = md5(uniqid(mt_rand(), true));
        $uuid = substr($chars, 0, 8) . '-';
        $uuid .= substr($chars, 8, 4) . '-';
        $uuid .= substr($chars, 12, 4) . '-';
        $uuid .= substr($chars, 16, 4) . '-';
        $uuid .= substr($chars, 20, 12);
        return $prefix . $uuid;

    }

    /**
     * 生成不重复的订单号
     *
     * @method orderNumber
     * @param  [type]      $seed [description]
     * @return [type]      [description]
     */
    public static function orderNumber()
    {
        return date('YmdHis').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 5);
    }

    /**
     * 生成订单
     * @return [type] [description]
     */
    public static function order_no()
    {
        return date('Ymd') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT);
    }

    /**
     * 获取附件默认图标
     */
    public static function attachment_icon($attachment)
    {
        $ext = pathinfo($attachment->title, PATHINFO_EXTENSION);
        switch ($ext) {
            case 'jpg':
            case 'jpeg':
            case 'png':
            case 'gif':
                $icon = $attachment->url;
                break;
            case 'doc':
            case 'docx':
                $icon = '/static/webapp/img/word.png';
                break;
            case 'xls':
            case 'xlsx':
                $icon = '/static/webapp/img/excel.png';
                break;
            case 'ppt':
            case 'pptx':
                $icon = '/static/webapp/img/ppt.png';
                break;
            case 'pdf':
                $icon = '/static/webapp/img/pdf.png';
                break;
            default:
                $icon = '/static/webapp/img/file_default.png';
        }
        return $icon;
    }

    /**
     * 友好日期时间
     *
     * @param DateTime $datetime 日期时间
     * @param int $size 精确到位数
     * @throws \InvalidArgumentException
     * @return string
     */
    public static function friendlyDate($datetime, $size=1)
    {
        if (is_int($datetime)) {
            $datetime = new \DateTime($datetime);
        }

        if (!($datetime instanceof \DateTime)) {
            throw new \InvalidArgumentException('invalid "DateTime" object');
        }

        $now = new \DateTime();
        $interval = $now->diff($datetime);

        $intervalData = array(
            $interval->y, $interval->m, $interval->d,
            $interval->h, $interval->i, $interval->s,
        );
        $intervalFormat = array('年', '个月', '天', '小时', '分钟', '秒');

        foreach($intervalData as $index=>$value) {
            if ($value) {
                $intervalData[$index] = $value . $intervalFormat[$index];
            } else {
                unset($intervalData[$index]);
                unset($intervalFormat[$index]);
            }
        }

        return implode('', array_slice($intervalData, 0, $size));
    }

    /**
     * 根据时间差美化时间
     * @param  [type] $diff [description]
     * @return [type]       [description]
     */
    public static function beautyTime($diff = 0)
    {
        $time = '';
        if ($diff < 60 && $diff > 0) {
            $time = $diff . '秒';
        }
        else if ($diff >= 60 && $diff < 60*60) {
            $time = $diff . '分钟';
        }
        else if ($diff >= 60*60 && $diff < 60*60*24) {
            $time = $diff . '小时';
        }
        else {
            $time = '超过一天';
        }
        return $time;
    }

    /**
     * 加密算法
     * @param unknown $txt
     * @param unknown $key
     */
    public static function encryptx($txt, $key)
    {
        $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
        $encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, utf8_encode($txt), MCRYPT_MODE_ECB, $iv);
        return self::base32Encode($encrypted_string);
    }

    /**
     * 解密算法
     * @param unknown $txt
     * @param unknown $key
     */
    public static function decryptx($txt, $key)
    {
        $txt = self::base32Decode($txt);
        $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
        $decrypted_string = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $txt, MCRYPT_MODE_ECB, $iv);
        return $decrypted_string;
    }


    public static function base32Encode($input)
    {
        // Reference: http://www.ietf.org/rfc/rfc3548.txt
        // If you want build alphabet own, you should modify the decode section too.
        $BASE32_ALPHABET = 'abcdefghijklmnopqrstuvwxyz234567';
        $output = '';
        $v = 0;
        $vbits = 0;

        for ($i = 0, $j = strlen($input); $i < $j; $i++) {
            $v <<= 8;
            $v += ord($input[$i]);
            $vbits += 8;

            while ($vbits >= 5) {
                $vbits -= 5;
                $output .= $BASE32_ALPHABET[$v >> $vbits];
                $v &= ((1 << $vbits) - 1);
            }
        }

        if ($vbits > 0) {
            $v <<= (5 - $vbits);
            $output .= $BASE32_ALPHABET[$v];
        }

        return $output;
    }
    public static function base32Decode($input)
    {
        $output = '';
        $v = 0;
        $vbits = 0;

        for ($i = 0, $j = strlen($input); $i < $j; $i++) {
            $v <<= 5;
            if ($input[$i] >= 'a' && $input[$i] <= 'z') {
                $v += (ord($input[$i]) - 97);
            } elseif ($input[$i] >= '2' && $input[$i] <= '7') {
                $v += (24 + $input[$i]);
            } else {
                return false;
                //exit(1);
                throw new \Exception("The value '{$input}' is not a base32Encode string");
            }

            $vbits += 5;
            while ($vbits >= 8) {
                $vbits -= 8;
                $output .= chr($v >> $vbits);
                $v &= ((1 << $vbits) - 1);
            }
        }
        return $output;
    }

    /**
     * 隐藏中间四位数字
     * @param unknown $phone
     * @return mixed
     */
    public static function maskTel($phone){
        $IsWhat = preg_match('/(0[0-9]{2,3}[\-]?[2-9][0-9]{6,7}[\-]?[0-9]?)/i',$phone); //固定电话
        if($IsWhat == 1){
            return preg_replace('/(0[0-9]{2,3}[\-]?[2-9])[0-9]{3,4}([0-9]{3}[\-]?[0-9]?)/i','$1****$2',$phone);
        }else{
            return  preg_replace('/(1[358]{1}[0-9])[0-9]{4}([0-9]{4})/i','$1****$2',$phone);
        }
    }

    /**
     * 数据掩码
     *
     * @param  [type] $idcard
     * @return [type]
     */
    public static function maskStar($str, $start, $length = 0)
    {
        $i = 0;
        $star = '';
        if($start >= 0) {
            if($length > 0) {
                $str_len = strlen($str);
                $count = $length;
                if($start >= $str_len) {//当开始的下标大于字符串长度的时候，就不做替换了
                    $count = 0;
                }
            } elseif($length < 0) {
                $str_len = strlen($str);
                $count = abs($length);
                if($start >= $str_len) {//当开始的下标大于字符串长度的时候，由于是反向的，就从最后那个字符的下标开始
                    $start = $str_len - 1;
                }
                $offset = $start - $count + 1;//起点下标减去数量，计算偏移量
                $count = $offset >= 0 ? abs($length) : ($start + 1);//偏移量大于等于0说明没有超过最左边，小于0了说明超过了最左边，就用起点到最左边的长度
                $start = $offset >= 0 ? $offset : 0;//从最左边或左边的某个位置开始
            } else {
                $str_len = strlen($str);
                $count = $str_len - $start;//计算要替换的数量
            }
        } else {
            if ($length > 0) {
                $offset = abs($start);
                $count = $offset >= $length ? $length : $offset;//大于等于长度的时候 没有超出最右边
            } elseif($length < 0){
                $str_len = strlen($str);
                $end = $str_len + $start;//计算偏移的结尾值
                $offset = abs($start + $length) - 1;//计算偏移量，由于都是负数就加起来
                $start = $str_len - $offset;//计算起点值
                $start = $start >= 0 ? $start : 0;
                $count = $end - $start + 1;
            }else {
                $str_len = strlen($str);
                $count = $str_len + $start + 1;//计算需要偏移的长度
                $start = 0;
            }
        }

        while ($i < $count) {
            $star .= '*';
            $i++;
        }

        return substr_replace($str, $star, $start, $count);
    }

    public static function cut_str($string, $sublen, $start = 0, $code = 'UTF-8')
    {
        if($code == 'UTF-8')
        {
            $pa = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|\xe0[\xa0-\xbf][\x80-\xbf]|[\xe1-\xef][\x80-\xbf][\x80-\xbf]|\xf0[\x90-\xbf][\x80-\xbf][\x80-\xbf]|[\xf1-\xf7][\x80-\xbf][\x80-\xbf][\x80-\xbf]/";
            preg_match_all($pa, $string, $t_string);
            if(count($t_string[0]) - $start > $sublen) return join('', array_slice($t_string[0], $start, $sublen));
            return join('', array_slice($t_string[0], $start, $sublen));
        }
        else
        {
            $start = $start*2;
            $sublen = $sublen*2;
            $strlen = strlen($string);
            $tmpstr = '';
            for($i=0; $i< $strlen; $i++)
            {
                if($i>=$start && $i< ($start+$sublen))
                {
                    if(ord(substr($string, $i, 1))>129)
                    {
                        $tmpstr.= substr($string, $i, 2);
                    }
                    else
                    {
                        $tmpstr.= substr($string, $i, 1);
                    }
                }
                if(ord(substr($string, $i, 1))>129) $i++;
            }
            //if(strlen($tmpstr)< $strlen ) $tmpstr.= "...";
            return $tmpstr;
        }
    }

    /**
     * 校验email格式
     *
     * @param  [type]  $str [description]
     * @return boolean      [description]
     */
    public static function isEmail($str)
    {
        $pa = '/^[a-zA-Z0-9_-]+([+][a-zA-Z0-9_-]+)*([.][a-zA-Z0-9_-]+)*[@][a-zA-Z0-9_-]+([.][a-zA-Z0-9_-]+)*[.][a-zA-Z]{2,4}$/';
        if (preg_match($pa, $str)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 验证手机号码
     * @param string $mobilephone
     * @return boolean
     */
    public static function isMobilePhone($mobilephone)
    {
        if (preg_match("/^1[3|5|8][0-9]{1}[0-9]{8}$/", $mobilephone)) {
            return true;
        } else {
            return false;
        }
    }


    /**
     * 替换html文件
     *
     */
    public static function html2text($str,$encode = 'utf-8'){
        $str = preg_replace("/<style .*?<\/style>/is", "", $str);
        $str = preg_replace("/<script .*?<\/script>/is", "", $str);
        $str = preg_replace("/\n|\r/", "", $str);//先把文本中所有的换行替换为空，避免下面替换换行时冲突
        $str = preg_replace("/<br\s?\/?>/i", "\n", $str);
        $str = preg_replace("/<\/p>/i", "\n\n", $str);
        $str = preg_replace("/<\/?td>/i", "\n", $str);
        $str = preg_replace("/<\/?div>/i", "\n", $str);
        $str = preg_replace("/<\/?blockquote>/i", "\n", $str);
        $str = preg_replace("/<\/?li>/i", "\n", $str);
        $str = preg_replace("/\&nbsp\;/i", " ", $str);
        $str = preg_replace("/\&amp\;/i", "&", $str);
        $str = preg_replace("/\&lt\;/i", "<", $str);
        $str = preg_replace("/\&gt\;/i", ">", $str);
        $str = preg_replace("/\&quot\;/i", '"', $str);
        $str = preg_replace("/\&ldquo\;/i", '“', $str);
        $str = preg_replace("/\&rdquo\;/i", '”', $str);
        $str = preg_replace("/\&lsquo\;/i", "‘", $str);
        $str = preg_replace("/\&rsquo\;/i", "’", $str);
        $str = preg_replace("/\&mdash\;/i", '—', $str);
        $str = preg_replace("/\&hellip\;/i", '…', $str);
        $str = preg_replace("/\&middot\;/i", '·', $str);
        $str = preg_replace("/\&times\;/i", '×', $str);
        //如果有特殊需求，请在本行下面按照以上格式继续加html特殊符号和转换后的符号
        $str = strip_tags($str);//去除空字符、html 和 php 标记
        $str = html_entity_decode($str, ENT_QUOTES, $encode);//解码双引号和单引号 &#039;
        $str = preg_replace("/\&\#.*?\;/i", "", $str); //替换所有&#开始;结尾的特殊字符
        return $str;
    }


    /**
     * 得到远程文件大小
     * @param unknown $url
     * @return string|NULL
     */
    public static function getFileSize($url){
        $url = parse_url($url);
        if($fp = @fsockopen($url['host'],empty($url['port'])?80:$url['port'],$error)){
            fputs($fp,"GET ".(empty($url['path'])?'/':$url['path'])." HTTP/1.1\r\n");
            fputs($fp,"Host:$url[host]\r\n\r\n");
            while(!feof($fp)){
                $tmp = fgets($fp);
                if(trim($tmp) == ''){
                    break;
                }else if(preg_match('/Content-Length:(.*)/si',$tmp,$arr)){
                    return trim($arr[1]);
                }
            }
            return null;
        }else{
            return null;
        }
    }

    /**
     * 二维数组排序
     * @param array $arr
     * @param string $direction
     * @param string $field
     * @return array
     */
    public static function arrSort($arr = [], $direction = 'SORT_DESC', $field = '')
    {
        $sort = array(
            'direction' => $direction, //排序顺序标志 SORT_DESC 降序；SORT_ASC 升序
            'field'     => $field,       //排序字段
        );
        $arrSort = array();
        foreach($arr AS $uniqid => $row){
            foreach($row AS $key => $value){
                $arrSort[$key][$uniqid] = $value;
            }
        }
        if($sort['direction']){
            array_multisort($arrSort[$sort['field']], constant($sort['direction']), $arr);
        }
        return $arr;
    }

    /**
     * 获取 IP  地理位置
     * 淘宝IP接口
     * @Return: array
     */
    public static function getCityTaobao($ip = '')
    {
        if($ip == ''){
            $url = "http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=json";//新浪
            $data = json_decode(file_get_contents($url), true);
            $location = $data['country'] . '-' . $data['province'] . '-' . $data['city'];
        }else{
            $url = "http://ip.taobao.com/service/getIpInfo.php?ip=".$ip;//淘宝
            $ip = json_decode(file_get_contents($url));
            if((string)$ip->code == '1'){
               return 'IP异常';
            }
            $data = (array)$ip->data;
            $location = $data['country'] . '-' . $data['region'] . '-' . $data['city'];
        }

        return $location;
    }

    /**
     * 根据腾讯IP分享计划的地址获取IP所在地，比较精确
     * @param  [type] $queryIP [description]
     * @return [type]          [description]
     */
    public static function getCityQQ($queryIP){
        $url = 'http://ip.qq.com/cgi-bin/searchip?searchip1='.$queryIP;

        $ch = curl_init($url);
        // curl_setopt($ch,CURLOPT_ENCODING ,'gb2312');
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true) ; // 获取数据返回
        $result = curl_exec($ch);
        // $result = mb_convert_encoding($result, "utf-8", "gb2312"); // 编码转换，否则乱码
        curl_close($ch);

        preg_match("@<span>(.*)</span></p>@iU", $result, $ipArray);
        $loc = $ipArray[1];

        return $loc;
    }

    /**
     * 获取用户真实 IP
     */
    public static function getIP()
    {
        $realip = '';
        if (isset($_SERVER)){
            if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])){
                $realip = $_SERVER["HTTP_X_FORWARDED_FOR"];
            } else if (isset($_SERVER["HTTP_CLIENT_IP"])) {
                $realip = $_SERVER["HTTP_CLIENT_IP"];
            } else {
                $realip = $_SERVER["REMOTE_ADDR"];
            }
        } else {
            if (getenv("HTTP_X_FORWARDED_FOR")){
                $realip = getenv("HTTP_X_FORWARDED_FOR");
            } else if (getenv("HTTP_CLIENT_IP")) {
                $realip = getenv("HTTP_CLIENT_IP");
            } else {
                $realip = getenv("REMOTE_ADDR");
            }
        }
        return $realip;
    }

}
